#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
# error "DATA_ORDER must be defined!"
#endif

#ifndef HASH_CBLOCK
# error "HASH_CBLOCK must be defined!"
#endif
#ifndef HASH_LONG
# error "HASH_LONG must be defined!"
#endif
#ifndef HASH_CTX
# error "HASH_CTX must be defined!"
#endif

#ifndef HASH_UPDATE
# error "HASH_UPDATE must be defined!"
#endif
#ifndef HASH_TRANSFORM
# error "HASH_TRANSFORM must be defined!"
#endif
#ifndef HASH_FINAL
# error "HASH_FINAL must be defined!"
#endif

#ifndef HASH_BLOCK_DATA_ORDER
# error "HASH_BLOCK_DATA_ORDER must be defined!"
#endif

#define ROTATE(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))

#if defined(DATA_ORDER_IS_BIG_ENDIAN)

# define HOST_c2l(c,l)  (l =(((unsigned long)(*((c)++)))<<24),          \
                         l|=(((unsigned long)(*((c)++)))<<16),          \
                         l|=(((unsigned long)(*((c)++)))<< 8),          \
                         l|=(((unsigned long)(*((c)++)))    )           )
# define HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)>>24)&0xff),      \
                         *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
                         *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
                         *((c)++)=(unsigned char)(((l)    )&0xff),      \
                         l)

#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)

# define HOST_c2l(c,l)  (l =(((unsigned long)(*((c)++)))    ),          \
                         l|=(((unsigned long)(*((c)++)))<< 8),          \
                         l|=(((unsigned long)(*((c)++)))<<16),          \
                         l|=(((unsigned long)(*((c)++)))<<24)           )
# define HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)    )&0xff),      \
                         *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
                         *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
                         *((c)++)=(unsigned char)(((l)>>24)&0xff),      \
                         l)

#endif

/*
 * Time for some action :-)
 */

int HASH_UPDATE(HASH_CTX* c, const void* data_, size_t len)
{
	const unsigned char* data = data_;
	unsigned char* p;
	HASH_LONG l;
	size_t n;

	if (len == 0)
		return 1;

	l = (c->Nl + (((HASH_LONG)len) << 3)) & 0xffffffffUL;
	if (l < c->Nl)              /* overflow */
		c->Nh++;
	c->Nh += (HASH_LONG)(len >> 29); /* might cause compiler warning on
									   * 16-bit */
	c->Nl = l;

	n = c->num;
	if (n != 0) {
		p = (unsigned char*)c->data;

		if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) {
			memcpy(p + n, data, HASH_CBLOCK - n);
			HASH_BLOCK_DATA_ORDER(c, p, 1);
			n = HASH_CBLOCK - n;
			data += n;
			len -= n;
			c->num = 0;
			/*
			 * We use memset rather than OPENSSL_cleanse() here deliberately.
			 * Using OPENSSL_cleanse() here could be a performance issue. It
			 * will get properly cleansed on finalisation so this isn't a
			 * security problem.
			 */
			memset(p, 0, HASH_CBLOCK); /* keep it zeroed */
		}
		else {
			memcpy(p + n, data, len);
			c->num += (unsigned int)len;
			return 1;
		}
	}

	n = len / HASH_CBLOCK;
	if (n > 0) {
		HASH_BLOCK_DATA_ORDER(c, data, n);
		n *= HASH_CBLOCK;
		data += n;
		len -= n;
	}

	if (len != 0) {
		p = (unsigned char*)c->data;
		c->num = (unsigned int)len;
		memcpy(p, data, len);
	}
	return 1;
}

void HASH_TRANSFORM(HASH_CTX* c, const unsigned char* data)
{
	HASH_BLOCK_DATA_ORDER(c, data, 1);
}

int HASH_FINAL(unsigned char* md, HASH_CTX* c)
{
	unsigned char* p = (unsigned char*)c->data;
	size_t n = c->num;

	p[n] = 0x80;                /* there is always room for one */
	n++;

	if (n > (HASH_CBLOCK - 8)) {
		memset(p + n, 0, HASH_CBLOCK - n);
		n = 0;
		HASH_BLOCK_DATA_ORDER(c, p, 1);
	}
	memset(p + n, 0, HASH_CBLOCK - 8 - n);

	p += HASH_CBLOCK - 8;
#if   defined(DATA_ORDER_IS_BIG_ENDIAN)
	(void)HOST_l2c(c->Nh, p);
	(void)HOST_l2c(c->Nl, p);
#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
	(void)HOST_l2c(c->Nl, p);
	(void)HOST_l2c(c->Nh, p);
#endif
	p -= HASH_CBLOCK;
	HASH_BLOCK_DATA_ORDER(c, p, 1);
	c->num = 0;

#ifndef HASH_MAKE_STRING
# error "HASH_MAKE_STRING must be defined!"
#else
	HASH_MAKE_STRING(c, md);
#endif

	return 1;
}

#ifndef MD32_REG_T
# if defined(__alpha) || defined(__sparcv9) || defined(__mips)
#  define MD32_REG_T long
/*
 * This comment was originally written for MD5, which is why it
 * discusses A-D. But it basically applies to all 32-bit digests,
 * which is why it was moved to common header file.
 *
 * In case you wonder why A-D are declared as long and not
 * as MD5_LONG. Doing so results in slight performance
 * boost on LP64 architectures. The catch is we don't
 * really care if 32 MSBs of a 64-bit register get polluted
 * with eventual overflows as we *save* only 32 LSBs in
 * *either* case. Now declaring 'em long excuses the compiler
 * from keeping 32 MSBs zeroed resulting in 13% performance
 * improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
 * Well, to be honest it should say that this *prevents*
 * performance degradation.
 */
# else
/*
 * Above is not absolute and there are LP64 compilers that
 * generate better code if MD32_REG_T is defined int. The above
 * pre-processor condition reflects the circumstances under which
 * the conclusion was made and is subject to further extension.
 */
#  define MD32_REG_T int
# endif
#endif
